#!/usr/bin/python

"""
 Module: getradiostream.py
 Ver: 1.0.0; Rev - Last 12/24/2012, Previous 12/21/2012

 Rev 1.0.0; Last = 12/24/2012, Previous - 12/21/2012 (AEM)
   - Original Releasez; 12/24/2012

 Dependencies:
     - streamripper must be installed to connect to radio station streams.
       On Debian/Ubuntu:
      $ sudo apt-get install streamripper

 Required local settings:
    - StreamRipperLoc = "<location of streamripper on the local system"
      Value is assigned from the config file

    - StreamName = Short name of stream source
    - StreamURL = URL of steam, most conveniently obtained from ShoutCast
    - StreamLoc = <path where stream files will be created>
      The preceeding 3 values are assigned from the config file but selected
      from the "Available Streams" combobox.

 Optional local settings:
     - StreamEndTime = Time to end stream capture, set from UI as hh:mm

 Copyright (C) 2012-2013  Arnold E. Morgan

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.

"""

import os
import subprocess
import sys
import time
import wx

StopTheStream = False
#DoLog = False
DoLog = True


def get_stream(myself, theStreamRipLoc, theStreamName, theStreamURL,
               theStreamLoc, theStreamET):
   """ The main stream session function that controls the
   subprocess while loop.
   """

   global StopTheStream
   global DoLog
   StreamRipperLoc = theStreamRipLoc
   StreamName = theStreamName
   StreamURL = theStreamURL
   StreamLoc = theStreamLoc
   StreamEndTime = theStreamET

   FailFlag = False
   StopTheStream = False
   StreamMssg = ""
   OneChar = ""
   LineList = []
   StreamLines = []

   #*** Save the last 2 captured lines ***
   StreamLines.append("")     # Holds current line as StreamLines[0]
   StreamLines.append("")     # Holds prior line as StreamLines[1]

   EndOnTime = False
   if len(StreamEndTime) > 0:
      EndOnTime = True

   command = [StreamRipperLoc, StreamURL, "--xs2", "-d", StreamLoc, "-r"]

   ConnectItems = ('*' * 30,
                   'EndOnTime: ' + str(EndOnTime),
                   'End Time: ' + StreamEndTime,
                   'Stop: ' + str(StopTheStream),
                   'Name: ' + StreamName,
                   'URL: ' + StreamURL,
                   'Loc: ' + StreamLoc,
                   'Ripper: ' + StreamRipperLoc,
                   'Save Stream Progress: ' + str(DoLog),
                   '*' * 30)

   send_connect_GUI_items(myself, ConnectItems)

   # -------------------------------------------------------------------
   if DoLog:
      TimeStampStr = time.strftime("%Y%m%d_%H%M%S", time.localtime())
      StreamLogName = "StreamOut_" + TimeStampStr + ".txt"
      StreamLog = open(StreamLogName, 'w', 0)
   # -------------------------------------------------------------------

   # BIG IMPORTANT NOTE: Send stderr to subproc stdout to capture messages
   #  from streams that are no longer active.
   # Leave out shell=True to allow terminating the subprocess on demand
   # and cleanly
   try:
      StreamSubProc = subprocess.Popen(command, stdout=subprocess.PIPE,
                                       stderr=subprocess.STDOUT)
   except OSError, err:
      FailFlag = True
      Mssg = "Cannot start stream process\nSubprocess error: %s" % err
      send_connect_GUI_mssg(myself, Mssg)
      restore_stream_ctrls(myself)
      sys.exit()
   except:
      FailFlag = True
      Mssg = "Unexpected subprocess start error: ", sys.exc_info()[0]
      send_connect_GUI_mssg(myself, Mssg)
      restore_stream_ctrls(myself)
      sys.exit()

   # -------------------------------------------------------------------
   # Main subprocess loop, here we go...
   # Read one char each loop interation. Need to watch for specific
   # sentinel characters to determine when to write stdout results to the
   # UI or the log.
   while StreamSubProc.poll() is None:
      TempTime = time.strftime("%H:%M:%S", time.localtime())
      OneChar = StreamSubProc.stdout.read(1)
      LineList.append(OneChar)

      # Terminate the subprocess at a certain time.
      if EndOnTime and TempTime[0:5] == StreamEndTime:
         StreamMssg = "Exiting at scheduled time %s" % TempTime
         send_connect_GUI_mssg(myself, StreamMssg)
         if DoLog:
            StreamLog.write("%s\n" % (StreamLines[1].rstrip('\n')))
            StreamLog.write(''.join(LineList))
            StreamLog.write('\n' + StreamMssg)

         StreamSubProc.terminate()
         break

      # If StopTheStream is set to True by the Pause button event,
      # do what it says.
      if StopTheStream:
         StreamMssg = "Pausing the stream at %s" % (TempTime)
         send_connect_GUI_mssg(myself, StreamMssg)
         if DoLog:
            StreamLog.write("%s\n" % (StreamLines[1].rstrip('\n')))
            StreamLog.write(''.join(LineList))
            StreamLog.write('\n' + StreamMssg)

         StreamSubProc.terminate()
         break

      # Also exit if a sentinel file exists.
      # Performing the path exists test too often causes characters
      #  to be missed. So check only on the minute (seconds == 00)
      if TempTime[-2:] == "00":
         if os.path.exists('stopme.xyz'):
            StreamMssg = "Exiting: File stopme.xyz exists"
            send_sonnect_GUI_mssg(myself, StreamMssg)
            if DoLog:
               StreamLog.write("%s\n" % (StreamLines[1].rstrip('\n')))
               StreamLog.write(''.join(LineList))
               StreamLog.write('\n' + StreamMssg)

            StreamSubProc.terminate()
            break

      if OneChar == "\r" or OneChar == "\n":
         send_update_GUI_mssg(myself, ''.join(LineList))
         StreamLines[1] = StreamLines[0]
         StreamLines[0] = ''.join(LineList)
         if OneChar == "\n":
            if StreamLines[0] == "\n":
               send_update_GUI_mssg(myself, StreamLines[1])
               send_insert_GUI_mssg(myself, '')

               if DoLog:
                  StreamLog.write("%s\n" % (StreamLines[1].rstrip('\n')))
            else:
               send_update_GUI_mssg(myself, StreamLines[0])
               send_insert_GUI_mssg(myself, '')
               if DoLog:
                  StreamLog.write("%s\n" % (StreamLines[0].rstrip('\n')))

         LineList[:] = []   # Empty all char elements. Ready to accumulate
                            # the next line.
      # End of StreamSubProc main while loop

   # StreamSubProc loop is done, clean up and end this thread.
   StreamSubProc.stdout.close()

   # -------------------------------------------------------------------
   if DoLog:
      StreamLog.close()

   restore_stream_ctrls(myself)
   send_connect_GUI_mssg(myself, "get_stream is done")
   # -------------------------------------------------------------------


def restore_stream_ctrls(myself):
   wx.MutexGuiEnter()
   myself.reset_stream_action_ctrls()
   wx.MutexGuiLeave()


def send_connect_GUI_items(myself, ConnectItems):
   wx.MutexGuiEnter()
   myself.add_new_connect_items(ConnectItems)
   wx.MutexGuiLeave()


def send_connect_GUI_mssg(myself, Mssg):
   wx.MutexGuiEnter()
   myself.add_new_connect_item((Mssg))
   wx.MutexGuiLeave()


def send_update_GUI_mssg(myself, Mssg):
   wx.MutexGuiEnter()
   myself.update_stream_content(Mssg.rstrip('\r\n'))
   wx.MutexGuiLeave()


def send_insert_GUI_mssg(myself, Mssg):
   wx.MutexGuiEnter()
   myself.insert_stream_content(Mssg.rstrip('\r\n'))
   wx.MutexGuiLeave()
